package server;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.SQLException;
import java.util.Hashtable;

import parameters.RlmServerParameters;
import server_multicast.ServerMulticast;
import utils.Constants;
import application.Application;
import connection_modul.DatabaseConnection;
import connection_modul.DatabaseModul;


/**
 * RAF_LAN_Messenger Server
 * 
 * @author Uros Krkic
 */
public class RLM_Server extends Thread implements Constants {
	
	private boolean started = false;
	private boolean running = true;
	private Application theApp;
	private ServerSocket listenSocket = null;
	
	/**
	 * Database connection modul koji obezbedjuje pool sa konekcijama sa bazom podataka.
	 */
	public static DatabaseModul databaseModul = null;

	
	/**
	 * Hash tabela koja cuva aktivne konekcije izmedju klijenata i servera.
	 * Aktivna konekcija se dodaje u hash tabelu kada se korisnik konekcije loguje,
	 * pri cemu je kljuc tabele jednak username-u korisnika.
	 */
	public static Hashtable<String, ServerSocketConnection> activeConnections = new Hashtable<String, ServerSocketConnection>();


	
	
	public RLM_Server(Application theApp) {
		this.theApp = theApp;
		this.theApp.setRlmServerReference(this);
	}
	
	
	@Override
	public void run() {
		try {
			
			databaseModul = new DatabaseModul(RlmServerParameters.getMaxDBConnections(), true);
			
//			listenSocket = new ServerSocket(RlmServerParameters.getServerPort());
			listenSocket = new ServerSocket();
			
			InetSocketAddress isa = new InetSocketAddress(InetAddress.getByName(RlmServerParameters.getNetworkInterfaceToConnect()), RlmServerParameters.getServerPort());
			listenSocket.bind(isa);
			
			listenSocket.setReuseAddress(true);
			
			started = true;
			
			printStartupMessage();
			
			setAllUsersToOfflineScript();
			
			InetAddress multicastAddress = InetAddress.getByName(RlmServerParameters.getMulticastIP());
			new ServerMulticast(multicastAddress, RlmServerParameters.getMulticastPort());
			
			Application.startSemaphore.release();
			
			// pokretanje thread-a koji proverava status konekcije sa klijentima
			ActiveConnectionsChecker acc = new ActiveConnectionsChecker(this);
			acc.setDaemon(true);
			acc.start();
			
			while ( running ) {
			
				Socket connectionSocket = listenSocket.accept();
				
				System.out.println( connectionSocket.getRemoteSocketAddress() );
				
				new ServerSocketConnection(connectionSocket);
//				taskQueue.execute( new ServerSocketConnection(connectionSocket) );
			}
		}
		catch (IOException ioe) {
//			ioe.printStackTrace();
		}
	}


	
	public void stopServer() {

		running = false;
		
		started = false;
		
//		databaseModul.closeConnections();
		
		try {
			listenSocket.close();
		}
		catch (IOException ioe) {
			ioe.printStackTrace();
		}
		
		this.interrupt();
		
		System.out.println("RLM SERVER STOPPED.");
	}
	
	
	public boolean isStarted() {
		return started;
	}
	
	
	
	/**
	 * Metod setuje sva polja statusa u tabeli tblUsers na 'Offline'.
	 * @author Uros Krkic
	 */
	private static void setAllUsersToOfflineScript() {
		DatabaseConnection dbConnection = new DatabaseConnection(databaseModul);
		
		String SQLUpdate = "UPDATE tblUsers SET tblUsers.status = 'Offline' " +
						   "WHERE tblUsers.username IS NOT NULL";
		
		try {
			dbConnection.doUpdateStatement(SQLUpdate);
			
		} catch (SQLException e) {
			e.printStackTrace();
			dbConnection.doRollBack();
		}
		
		dbConnection.doCommit();
		
		dbConnection.closeConnection();
	}
	
	
	
	/**
	 * Metod stampa startup poruku.
	 * @author Uros Krkic
	 */
	private static void printStartupMessage() {
		StringBuffer messageBuffer = new StringBuffer();
		
		messageBuffer.append("RLM Server running at:\n");
		messageBuffer.append("IP address: ");
		
		try {
			messageBuffer.append(InetAddress.getLocalHost().getHostAddress());
		}
		catch (UnknownHostException e) {
			e.printStackTrace();
		}
		
		messageBuffer.append("\nPort: ");
		messageBuffer.append(RlmServerParameters.getServerPort());
		messageBuffer.append("\n============================");
		messageBuffer.append("\nParallel DB Connections: ");
		messageBuffer.append(RlmServerParameters.getMaxDBConnections());
		messageBuffer.append("\n============================");
		
		System.out.println(messageBuffer.toString());
	}
	
	
	public void closeAllDBConnections() {
		databaseModul.closeConnections();
	}
	
}
